﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Reflection.PortableExecutable;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace Common
{
    /// <summary>
    /// 两个exe程序之间通信_共享内存传递（主从运行，不可单独运行）
    /// </summary>
    public class SharedMemoryHelper
    {
        /*
         * 二进制 100=0x1100100
         * 
         * 注意一：线程或进程间通讯时使用互斥锁
         * //bool mutexCreated;
         * //Mutex mutex = newMutex(true, "testmapmutex", out mutexCreated);  // 创建锁(指定锁名)
         * //try{
         * //    mutex.WaitOne();  // 等待其他程序释放锁
         * //    // 通讯处理...
         * //}
         * //finally{
         * //    mutex.ReleaseMutex();  // 释放锁
         * //}
         * 
         * 注意二：非持久文件映射时，注意MemoryMappedFile不要被GC。
         * 
         */

        #region 非持久文件映射
        /*
         * 1、非持久文件映射
         * 非持久文件是未与磁盘上的源文件关联的内存映射文件。
         * 当最后一个进程使用完此文件后，数据将丢失，并且垃圾回收功能将回收此文件。
         * 可使用非托管对象防止被回收
         */

        private static MemoryMappedFile? mmf_NoKeep = null;

        /**
         * 内存共享_空间
         */
        private static long capacity = 1024 * 1024 * 100;  // 100MB ;

        /// <summary>
        /// 内存共享_基于流的操作_读-非持久文件映射
        /// </summary>
        /// <param name="mmfName">共享内容对象名</param>
        /// <returns></returns>
        public static MemoryMappedFile_ShareInfo_ViewStream MemoryMappedFile_ViewStream_Read_NoKeep(string mmfName)
        {
            MemoryMappedFile_ShareInfo_ViewStream resultShareInfo = null;

            if (mmf_NoKeep == null)
            {
                mmf_NoKeep = MemoryMappedFile.CreateOrOpen(mmfName, capacity, MemoryMappedFileAccess.ReadWrite);  // 打开共享内存区域，大小默认为100MB
            }
            using (MemoryMappedViewStream stream = mmf_NoKeep.CreateViewStream())
            {
                if (stream.CanRead)
                {
                    BinaryReader reader = new(stream);
                    var data = reader.ReadString();
                    if (!String.IsNullOrWhiteSpace(data))
                    {
                        resultShareInfo = data.ToObject<MemoryMappedFile_ShareInfo_ViewStream>();
                        //if (JsonConvert.DeserializeObject<MemoryMappedFile_ShareInfo_ViewStream>(reader.ReadString()) is MemoryMappedFile_ShareInfo_ViewStream share)
                        //{
                        //    resultShareInfo = share;
                        //}
                        //todo 读取过的内容清除掉
                        BinaryWriter writer = new BinaryWriter(stream);
                        writer.Seek(0, SeekOrigin.Begin);
                        writer.Write("");
                        writer.Flush();
                    }
                }
            }
            return resultShareInfo;
        }

        /// <summary>
        /// 内存共享_基于内存偏移量的操作_读-非持久文件映射
        /// </summary>
        /// <param name="mmfName">共享内容对象名</param>
        /// <returns></returns>
        public static MemoryMappedFile_ShareInfo_ViewAccessor MemoryMappedFile_ViewAccessor_Read_NoKeep(string mmfName)
        {
            MemoryMappedFile_ShareInfo_ViewAccessor resultShareInfo = new();
            if (mmf_NoKeep == null)
            {
                mmf_NoKeep = MemoryMappedFile.CreateOrOpen(mmfName, capacity, MemoryMappedFileAccess.ReadWrite);  // 打开共享内存区域，大小默认为100MB
            }
            using (MemoryMappedViewAccessor accessor = mmf_NoKeep.CreateViewAccessor(0, 100))  // 注意这里的偏移量,大小；大小100MB
            {
                int colorSize = Marshal.SizeOf(typeof(MemoryMappedFile_ShareInfo_ViewAccessor));
                accessor.Read(0, out resultShareInfo);  // 读取视图
            }
            return resultShareInfo;
        }

        /// <summary>
        /// 内存共享_基于流的操作_写-非持久文件映射
        /// </summary>
        /// <param name="mmfName">共享内容对象名</param>
        /// <param name="share">写入的内容</param>
        public static bool MemoryMappedFile_ViewStream_Wirte_NoKeep(string mmfName, MemoryMappedFile_ShareInfo_ViewStream shareInfo)
        {
            bool result = false;
            if (mmf_NoKeep == null)
            {
                mmf_NoKeep = MemoryMappedFile.CreateOrOpen(mmfName, capacity, MemoryMappedFileAccess.ReadWrite);  // 打开共享内存区域，大小默认为100MB
            }
            using (MemoryMappedViewStream stream = mmf_NoKeep.CreateViewStream())
            {
                result = stream.CanWrite;
                if (result)
                {
                    BinaryWriter writer = new(stream);
                    writer.Write(shareInfo.ToJsonString());
                    writer.Flush();
                    //writer.Write(JsonConvert.SerializeObject(shareInfo));
                }
            }
            return result;
        }

        /// <summary>
        /// 内存共享_基于内存偏移量的操作_写-非持久文件映射
        /// </summary>
        /// <param name="mmfName"></param>
        /// <param name="shareInfo"></param>
        /// <returns></returns>
        public static bool MemoryMappedFile_ViewAccessor_Wirte_NoKeep(string mmfName, MemoryMappedFile_ShareInfo_ViewAccessor shareInfo)
        {
            bool result = false;
            if (mmf_NoKeep == null)
            {
                mmf_NoKeep = MemoryMappedFile.CreateOrOpen(mmfName, capacity, MemoryMappedFileAccess.ReadWrite);  // 打开共享内存区域，大小默认为100MB 
            }
            using (MemoryMappedViewAccessor accessor = mmf_NoKeep.CreateViewAccessor(0, 100))  // 注意这里的偏移量,大小；大小100MB
            {
                result = accessor.CanRead;
                if (result)
                {
                    int colorSize = Marshal.SizeOf(typeof(MemoryMappedFile_ShareInfo_ViewAccessor));
                    // 视图操作
                    accessor.Write(0, ref shareInfo);  // 修改视图
                }
            }
            return result;
        }
        #endregion 非持久文件映射

        #region 持久文件映射
        /* 
         * 2、持久文件映射
         * 持久文件是与磁盘上的源文件关联的内存映射文件。
         * 在最后一个进程使用完此文件后，数据将保存到磁盘上的源文件中。这些内存映射文件适合用来处理非常大的源文件。
         * 不需要考虑维护共享内存对象被回收的问题
         */

        /// <summary>
        /// 内存共享_基于流的操作_读-持久文件映射
        /// </summary>
        /// <param name="mmfFile">共享内容对象的文件路径</param>
        /// <param name="mmfName">共享内容对象名</param>
        /// <returns></returns>
        public static MemoryMappedFile_ShareInfo_ViewStream MemoryMappedFile_ViewStream_Read_Keep(string mmfFile, string mmfName)
        {
            MemoryMappedFile_ShareInfo_ViewStream resultShareInfo = new();

            using (MemoryMappedFile mmf_Keep = MemoryMappedFile.CreateFromFile(mmfFile, FileMode.OpenOrCreate, mmfName, capacity))  // "D:\\内存映射文件.data",默认100MB
            {
                using (MemoryMappedViewStream stream = mmf_Keep.CreateViewStream())
                {
                    if (stream.CanRead)
                    {
                        BinaryReader reader = new(stream);
                        var data = reader.ReadString();
                        if (!String.IsNullOrWhiteSpace(data))
                        {
                            resultShareInfo = data.ToObject<MemoryMappedFile_ShareInfo_ViewStream>();
                            //if (JsonConvert.DeserializeObject<MemoryMappedFile_ShareInfo_ViewStream>(reader.ReadString()) is MemoryMappedFile_ShareInfo_ViewStream share)
                            //{
                            //    resultShareInfo = share;
                            //}
                        }
                    }
                }
            }
            return resultShareInfo;
        }

        /// <summary>
        /// 内存共享_基于内存偏移量的操作_读-持久文件映射
        /// </summary>
        /// <param name="mmfFile">共享内容对象的文件路径</param>
        /// <param name="mmfName">共享内容对象名</param>
        /// <returns></returns>
        public static MemoryMappedFile_ShareInfo_ViewAccessor MemoryMappedFile_ViewAccessor_Read_Keep(string mmfFile, string mmfName)
        {
            MemoryMappedFile_ShareInfo_ViewAccessor resultShareInfo = new();

            using (MemoryMappedFile mmf_Keep = MemoryMappedFile.CreateFromFile(mmfFile, FileMode.OpenOrCreate, mmfName, capacity))  // "D:\\内存映射文件.data",默认100MB
            {
                using (MemoryMappedViewAccessor accessor = mmf_Keep.CreateViewAccessor(0, 100))  // 注意这里的偏移量,大小；大小需要调整
                {
                    int colorSize = Marshal.SizeOf(typeof(MemoryMappedFile_ShareInfo_ViewAccessor));
                    // 视图操作
                    accessor.Read(0, out resultShareInfo);  // 读取视图
                }
            }

            return resultShareInfo;
        }

        /// <summary>
        /// 内存共享_基于流的操作_写-持久文件映射
        /// </summary>
        /// <param name="mmfFile">共享内容对象的文件路径</param>
        /// <param name="mmfName">共享内容对象名</param>
        /// <param name="share">写入的内容</param>
        public static bool MemoryMappedFile_ViewStream_Wirte_Keep(string mmfFile, string mmfName, MemoryMappedFile_ShareInfo_ViewStream shareInfo)
        {
            bool result = false;
            using (MemoryMappedFile mmf_Keep = MemoryMappedFile.CreateFromFile(mmfFile, FileMode.OpenOrCreate, mmfName, capacity))  // "D:\\内存映射文件.data",默认100MB
            {
                using (MemoryMappedViewStream stream = mmf_Keep.CreateViewStream())
                {
                    result = stream.CanWrite;
                    if (result)
                    {
                        BinaryWriter writer = new(stream);
                        writer.Write(shareInfo.ToJsonString());
                        //writer.Write(JsonConvert.SerializeObject(shareInfo));
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// 内存共享_基于内存偏移量的操作_写-持久文件映射
        /// </summary>
        /// <param name="mmfFile">共享内容对象的文件路径</param>
        /// <param name="mmfName">共享内容对象名</param>
        /// <param name="share">写入的内容（二进制，单位MB）</param>
        public static bool MemoryMappedFile_ViewAccessor_Wirte_Keep(string mmfFile, string mmfName, MemoryMappedFile_ShareInfo_ViewAccessor shareInfo)
        {
            bool result = false;

            using (MemoryMappedFile mmf_Keep = MemoryMappedFile.CreateFromFile(mmfFile, FileMode.OpenOrCreate, mmfName, capacity))  // "D:\\内存映射文件.data",默认100MB
            {
                using (MemoryMappedViewAccessor accessor = mmf_Keep.CreateViewAccessor(0, 100))  // 注意这里的偏移量,大小；大小需要调整
                {
                    result = accessor.CanRead;
                    if (result)
                    {
                        int colorSize = Marshal.SizeOf(typeof(MemoryMappedFile_ShareInfo_ViewAccessor));
                        // 视图操作
                        accessor.Write(0, ref shareInfo);  // 修改视图
                    }
                }
            }
            return result;
        }
        #endregion 持久文件映射

        /// <summary>
        /// 共享内存传递_发送
        /// </summary>
        /// <param name="shareName"></param>
        /// <param name="radIsStream"></param>
        /// <param name="chkIsKeep"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        public static Boolean SendMsg(String shareName, Boolean radIsStream, Boolean chkIsKeep, Object content)
        {
            bool result = false;

            var sharePath = System.IO.Path.Combine(WorkPath.ExecPath, "share", $"{shareName}.dat");
            // 内存共享_基于流的操作_写-持久文件映射
            if (radIsStream && chkIsKeep)
            {
                MemoryMappedFile_ShareInfo_ViewStream shareInfo = new();
                shareInfo.SessionIdGUID = "1";
                shareInfo.CreateTime = DateTime.Now;
                shareInfo.InfoData = content;

                result = MemoryMappedFile_ViewStream_Wirte_Keep(sharePath, shareName, shareInfo);
            }
            // 内存共享_基于流的操作_写-非持久文件映射
            else if (radIsStream && !chkIsKeep)
            {
                MemoryMappedFile_ShareInfo_ViewStream shareInfo = new();
                shareInfo.SessionIdGUID = "1";
                shareInfo.CreateTime = DateTime.Now;
                shareInfo.InfoData = content;

                result = MemoryMappedFile_ViewStream_Wirte_NoKeep(shareName, shareInfo);
            }
            // 内存共享_基于内存偏移量的操作_写-持久文件映射
            else if (!radIsStream && chkIsKeep)
            {
                MemoryMappedFile_ShareInfo_ViewAccessor shareInfo = new();
                shareInfo.SessionIdGUID = 1;
                shareInfo.CreateTime = DateTime.Now;
                shareInfo.InfoData = Convert.ToInt64(content);

                //result = MemoryMappedFile_ViewAccessor_Wirte_Keep(txtShareFilePath.Text.Trim(), txtShareName.Text.Trim(), shareInfo);
                result = MemoryMappedFile_ViewAccessor_Wirte_Keep(sharePath, shareName, shareInfo);
            }
            // 内存共享_基于内存偏移量的操作_写-非持久文件映射
            else if (!radIsStream && !chkIsKeep)
            {
                MemoryMappedFile_ShareInfo_ViewAccessor shareInfo = new();
                shareInfo.SessionIdGUID = 1;
                shareInfo.CreateTime = DateTime.Now;
                shareInfo.InfoData = Convert.ToInt64(content);

                result = MemoryMappedFile_ViewAccessor_Wirte_NoKeep(shareName, shareInfo);  //
            }
            return result;
        }

        /// <summary>
        /// 共享内存方式-手动获取（根据需要加互斥锁或进程内线程锁）
        /// </summary>
        /// <param name="shareName"></param>
        /// <param name="radIsStream"></param>
        /// <param name="chkIsKeep"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        public static bool TryGetMsg(String shareName, Boolean radIsStream, Boolean chkIsKeep, out Object content)
        {
            bool result = false;
            content = null;

            var sharePath = System.IO.Path.Combine(WorkPath.ExecPath, "share", $"{shareName}.dat");
            // 内存共享_基于流的操作_写-持久文件映射
            if (radIsStream && chkIsKeep)
            {
                MemoryMappedFile_ShareInfo_ViewStream shareInfo = MemoryMappedFile_ViewStream_Read_Keep(sharePath, shareName);
                if (shareInfo != null)
                {
                    content = shareInfo.InfoData;
                    result = true;
                    //"信息序号：" + shareInfo.SessionIdGUID + ";发送时间：" + shareInfo.CreateTime + ";内容：" + (!string.IsNullOrEmpty(infoData) ? infoData : string.Empty);
                }
                else
                {
                    //rTxtShareMemo_msg.Text = "未获取到数据！";
                }
            }
            // 内存共享_基于流的操作_写-非持久文件映射
            else if (radIsStream && !chkIsKeep)
            {
                MemoryMappedFile_ShareInfo_ViewStream shareInfo = MemoryMappedFile_ViewStream_Read_NoKeep(shareName);
                if (shareInfo != null)
                {
                    content = shareInfo.InfoData;
                    result = true;
                    //rTxtShareMemo_msg.Text = "信息序号：" + shareInfo.SessionIdGUID + ";发送时间：" + shareInfo.CreateTime + ";内容：" + (!string.IsNullOrEmpty(infoData) ? infoData : string.Empty);
                }
                else
                {
                    // rTxtShareMemo_msg.Text = "未获取到数据！";
                }
            }
            // 内存共享_基于内存偏移量的操作_写-持久文件映射
            else if (!radIsStream && chkIsKeep)
            {
                MemoryMappedFile_ShareInfo_ViewAccessor shareInfo = MemoryMappedFile_ViewAccessor_Read_Keep(sharePath, shareName);

                content = (long)shareInfo.InfoData;
                result = true;
                //rTxtShareMemo_msg.Text = "信息序号：" + shareInfo.SessionIdGUID + ";发送时间：" + shareInfo.CreateTime + ";内容：" + (long)shareInfo.InfoData;
            }
            // 内存共享_基于内存偏移量的操作_写-非持久文件映射
            else if (!radIsStream && !chkIsKeep)
            {
                MemoryMappedFile_ShareInfo_ViewAccessor shareInfo = MemoryMappedFile_ViewAccessor_Read_NoKeep(shareName);
                content = (long)shareInfo.InfoData;
                result = true;
                // rTxtShareMemo_msg.Text = "信息序号：" + shareInfo.SessionIdGUID + ";发送时间：" + shareInfo.CreateTime + ";内容：" + (long)shareInfo.InfoData;
            }

            return result;
        }

        /// <summary>
        /// 共享内存_基于流的
        /// </summary>
        public class MemoryMappedFile_ShareInfo_ViewStream
        {
            /// <summary>
            /// 标识ID
            /// </summary>
            public string SessionIdGUID { set; get; } = string.Empty;

            /// <summary>
            /// 创建时间
            /// </summary>
            public DateTime CreateTime { set; get; } = DateTime.Now;

            /// <summary>
            /// 自定义的共享信息
            /// </summary>
            public object InfoData { set; get; } = new object();
        }

        /// <summary>
        /// 共享内存_基于偏移量的
        /// </summary>
        public struct MemoryMappedFile_ShareInfo_ViewAccessor
        {
            /// <summary>
            /// 标识ID
            /// </summary>
            public int SessionIdGUID { set; get; } = 0;

            /// <summary>
            /// 创建时间
            /// </summary>
            public DateTime CreateTime { set; get; } = DateTime.Now;

            /// <summary>
            /// 自定义的共享信息
            /// </summary>
            public long InfoData { set; get; } = 0;

            public MemoryMappedFile_ShareInfo_ViewAccessor()
            {

            }
        }
    }
}
